import { PerformanceMonitor } from './PerformanceMonitor';
import { registryEntityNodeByUUID, registryNodeSystem } from './Registry';

/**
 * Time类负责管理游戏的时间系统和更新循环
 *
 * 该类实现了以下主要功能：
 * 1. 维护游戏的时间更新循环
 * 2. 控制组件和系统的更新顺序
 * 3. 确保更新间隔在合理范围内
 * 4. 提供时间系统的启动、停止和状态查询功能
 */
class Time {
  /** 最大允许的时间间隔（毫秒），用于防止过大的时间步长 */
  private static readonly MAX_DELTA_TIME = 1000;
  /** 定时器ID，用于控制更新循环 */
  private _timeId: number = 0;
  /** 上一次更新的时间戳 */
  private _lastUpdateDate: number = 0;
  /** 时间缩放因子，用于控制游戏时间流速 */
  private _timeScale: number = 1;

  private _lastFpsUpdate: number = 0;

  /** 延时任务队列 */
  private _timeoutTasks: Map<number, { callback: () => void; time: number }> =
    new Map();
  /** 任务ID计数器 */
  private _taskIdCounter: number = 0;

  /** 时间扭曲效果持续时间 */
  private _timeWarpDuration: number = 0;
  /** 时间扭曲效果强度 */
  private _timeWarpIntensity: number = 1;

  constructor() {
    this.updateFunc = this.updateFunc.bind(this);
    this._lastFpsUpdate = Date.now();

    this.start();
  }

  /**
   * 启动时间系统
   * 初始化时间戳并开始更新循环
   */
  start() {
    if (!this._timeId) {
      this._lastUpdateDate = Date.now();
      this._timeId = setInterval(
        this.updateFunc,
        PerformanceMonitor.FRAME_TIME_THRESHOLD
      );
    }
  }

  /**
   * 检查时间系统是否正在运行
   * @returns {boolean} 返回时间系统的运行状态
   */
  isRunning(): boolean {
    return !!this._timeId;
  }

  /**
   * 设置dt时间缩放因子
   * @param scale - 时间缩放因子，默认为1
   */
  setTimeScale(scale: number) {
    this._timeScale = Math.max(0, scale);
  }

  /**
   * 获取当前dt时间缩放因子
   */
  getTimeScale(): number {
    return this._timeScale;
  }

  /**
   * 添加延时任务
   * @param callback - 回调函数
   * @param delay - 延迟时间（毫秒）
   * @returns 任务ID
   */
  setTimeout(callback: () => void, delay: number): number {
    const taskId = this._taskIdCounter++;
    this._timeoutTasks.set(taskId, {
      callback,
      time: Date.now() + delay,
    });
    return taskId;
  }

  /**
   * 清除延时任务
   * @param taskId - 任务ID
   */
  clearTimeout(taskId: number) {
    this._timeoutTasks.delete(taskId);
  }

  /**
   * 停止时间系统
   * 清除定时器并重置时间ID
   */
  stop() {
    if (this._timeId) {
      clearInterval(this._timeId);
      this._timeId = 0;
    }
  }

  /**
   * 应用时间扭曲效果
   * @param intensity - 时间扭曲强度
   * @param duration - 持续时间（毫秒）
   */
  applyTimeWarp(intensity: number, duration: number) {
    this._timeWarpIntensity = intensity;
    this._timeWarpDuration = Math.max(0, duration);
  }

  /**
   * 更新所有实体节点的组件
   * @param deltaTime - 距离上次更新的时间间隔（毫秒）
   * @param isLateUpdate - 是否为延迟更新阶段
   */
  private updateComponents(deltaTime: number, isLateUpdate: boolean = false) {
    for (const node of registryEntityNodeByUUID.values()) {
      try {
        if (isLateUpdate) {
          // @ts-expect-error
          node.lateUpdateFunc?.(deltaTime);
        } else {
          // @ts-expect-error
          node.updateFunc?.(deltaTime);
        }
      } catch (error) {
        console.error(
          `组件${isLateUpdate ? 'late' : ''}更新错误: ${node.uuid}`,
          error
        );
      }
    }
  }

  /**
   * 更新所有系统
   * @param deltaTime - 距离上次更新的时间间隔（毫秒）
   * @param isLateUpdate - 是否为延迟更新阶段
   */
  private updateSystems(deltaTime: number, isLateUpdate: boolean = false) {
    for (const system of registryNodeSystem.values()) {
      try {
        if (system.enable) {
          if (isLateUpdate) {
            // @ts-expect-error
            system.postUpdate?.(deltaTime);
          } else {
            // @ts-expect-error
            system.update?.(deltaTime);
          }
        }
      } catch (error) {
        const systemName = system.constructor.name;
        console.error(
          `系统${isLateUpdate ? 'late' : ''}更新错误: ${systemName}`,
          error
        );
      }
    }
  }

  /**
   * 主更新函数
   * 计算时间间隔并按顺序执行更新：
   * 1. 更新组件
   * 2. 更新系统
   * 3. 延迟更新组件
   * 4. 延迟更新系统
   */
  private updateFunc() {
    try {
      const now = Date.now();
      const deltaTime = Math.min(
        now - this._lastUpdateDate,
        Time.MAX_DELTA_TIME
      );
      if (deltaTime <= 0) {
        return;
      }

      // 应用时间扭曲效果
      let effectiveTimeScale = this._timeScale;
      if (this._timeWarpDuration > 0) {
        effectiveTimeScale *= this._timeWarpIntensity;
        this._timeWarpDuration = Math.max(
          0,
          this._timeWarpDuration - deltaTime
        );
      }

      // 应用时间缩放
      const scaledDeltaTime = deltaTime * effectiveTimeScale;

      // 按顺序执行更新
      this.updateComponents(scaledDeltaTime);
      this.updateSystems(scaledDeltaTime);
      this.updateComponents(scaledDeltaTime, true);
      this.updateSystems(scaledDeltaTime, true);

      // 处理延时任务
      const expiredTasks = new Map();
      for (const [taskId, task] of this._timeoutTasks) {
        if (now >= task.time) {
          expiredTasks.set(taskId, task);
        }
      }

      // 分离任务执行和删除操作
      for (const [taskId, task] of expiredTasks) {
        try {
          task.callback();
        } catch (error) {
          console.error(`延时任务执行错误: ${taskId}`, error);
        } finally {
          this._timeoutTasks.delete(taskId);
        }
      }

      this._lastUpdateDate = now;
    } catch (error) {
      console.error('时间系统更新错误:', error);
    }
  }
}

export const NodeTime = new Time();
